﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;
using System.IO;
using System.Windows.Input;
using ImageTools.IO.Gif;
using ImageTools;
using System.Reflection;

namespace UI
{
    public partial class MainPage : PhoneApplicationPage
    {
        private ObservableCollection<Tweet> tweets = new ObservableCollection<Tweet>();

        private ObservableCollection<User> following = new ObservableCollection<User>();

        private Dictionary<string, ApplicationBarIconButton> barIconButtonCollection = new Dictionary<string, ApplicationBarIconButton>();

        private Run validCharCount;

        private Run invalidCharCount;

        private LoadingIndicatorController loadingIndicatorController;

        private bool isGettingTweet;

        public MainPage()
        {
            InitializeComponent();
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            this.Loaded -= PhoneApplicationPage_Loaded;

            TiltEffect.TiltableItems.Add(typeof(MenuItem));
            TiltEffect.TiltableItems.Add(typeof(TiltContainer));

            ScrollViewer scrollViewer = VisualTreeHelper.GetChild(this.tweetsListBox, 0) as ScrollViewer;
            FrameworkElement border = VisualTreeHelper.GetChild(scrollViewer, 0) as FrameworkElement;
            VisualStateGroup scrollStates = VisualStateManager.GetVisualStateGroups(border)[0] as VisualStateGroup;
            scrollStates.CurrentStateChanging += scrollStates_CurrentStateChanging;

            List<ScrollBar> scrollBarList = CommonHelper.GetVisualChildCollection<ScrollBar>(scrollViewer);
            ScrollBar bar = scrollBarList.Where(x => x.Name == "VerticalScrollBar").First();
            bar.Background = new SolidColorBrush(Color.FromArgb(0xff, 0x99, 0x99, 0x99));

            ApplicationBarIconButton button;

            button = new ApplicationBarIconButton(new Uri("/Images/publish.png", UriKind.Relative));
            button.Text = "发布";
            button.Click += publishButton_Click;
            button.IsEnabled = false;
            barIconButtonCollection.Add("publishButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/cancel.png", UriKind.Relative));
            button.Text = "取消";
            button.Click += cancelButton_Click;
            button.IsEnabled = false;
            barIconButtonCollection.Add("cancelButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/refresh.png", UriKind.Relative));
            button.Text = "刷新";
            button.Click += refreshButton_Click;
            barIconButtonCollection.Add("refreshButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/write.png", UriKind.Relative));
            button.Text = "新建";
            button.Click += writeButton_Click;
            barIconButtonCollection.Add("writeButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/picture.png", UriKind.Relative));
            button.Text = "图片";
            button.Click += pictureButton_Click;
            button.IsEnabled = false;
            barIconButtonCollection.Add("pictureButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/follow.png", UriKind.Relative));
            button.Text = "加关注";
            button.Click += followButton_Click;
            button.IsEnabled = true;
            barIconButtonCollection.Add("followButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/return.png", UriKind.Relative));
            button.Text = "返回";
            button.Click += returnButton_Click;
            button.IsEnabled = true;
            barIconButtonCollection.Add("returnButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/searchuser.png", UriKind.Relative));
            button.Text = "搜索";
            button.Click += searchUserButton_Click;
            button.IsEnabled = false;
            barIconButtonCollection.Add("searchUserButton", button);

            button = new ApplicationBarIconButton(new Uri("/Images/add.png", UriKind.Relative));
            button.Text = "添加";
            button.Click += addUserButton_Click;
            button.IsEnabled = false;
            barIconButtonCollection.Add("addUserButton", button);

            ApplicationBarMenuItem logoutMenuItem = new ApplicationBarMenuItem("注销");
            logoutMenuItem.Click += logoutMenuItem_Click;
            this.ApplicationBar.MenuItems.Add(logoutMenuItem);

            ApplicationBarMenuItem aboutMenuItem = new ApplicationBarMenuItem("关于");
            aboutMenuItem.Click += aboutMenuItem_Click;
            this.ApplicationBar.MenuItems.Add(aboutMenuItem);

            Run run;
            run = new Run() { Text = "还可以输入" };
            this.validCharCountTextBlock.Inlines.Add(run);
            run = new Run() { Text = "280", FontWeight = FontWeights.Bold };
            validCharCount = run;
            this.validCharCountTextBlock.Inlines.Add(run);
            run = new Run() { Text = "个字符" };
            this.validCharCountTextBlock.Inlines.Add(run);

            run = new Run() { Text = "已经超过" };
            this.invalidCharCountTextBlock.Inlines.Add(run);
            run = new Run() { Text = "0", Foreground = new SolidColorBrush(Color.FromArgb(0xff, 0xc0, 0x50, 0x4d)), FontWeight = FontWeights.Bold };
            invalidCharCount = run;
            this.invalidCharCountTextBlock.Inlines.Add(run);
            run = new Run() { Text = "个字符" };
            this.invalidCharCountTextBlock.Inlines.Add(run);

            this.tweetsListBox.ItemsSource = this.tweets;

            this.tweetImage.Source = new BitmapImage();
            ContextMenu menu = new ContextMenu();
            menu.IsZoomEnabled = false;
            MenuItem item = new MenuItem();
            item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
            item.Header = "删除";
            item.Click += new RoutedEventHandler(DeleteTweetImage_Click);
            menu.Items.Add(item);
            ContextMenuService.SetContextMenu(this.tweetImage, menu);

            loadingIndicatorController = new LoadingIndicatorController(this.loadingIndicator);

            isGettingTweet = true;
            loadingIndicatorController.Add();
            OAuthHelper.AccessProtectedResource(ConfigHelper.TimelineAPI, null, GetTimeLineCompleted, null);
        }

        private void GetTimeLineCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            IEnumerable<XElement> xmlTweets = xmlResult.Root.Elements("statuses");
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    this.FillTweetCollection(xmlTweets, false);
                    isGettingTweet = false;
                    loadingIndicatorController.Minus();
                }
            );
        }

        private void DeleteTweetImage_Click(object sender, RoutedEventArgs e)
        {
            this.tweetImageContainer.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void scrollStates_CurrentStateChanging(object sender, VisualStateChangedEventArgs e)
        {
            if (e.NewState.Name == "NotScrolling")
            {
                ScrollViewer scrollViewer = VisualTreeHelper.GetParent(sender as FrameworkElement) as ScrollViewer;
                if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
                {
                    if (isGettingTweet == false && tweets.Count > 0)
                    {
                        isGettingTweet = true;
                        Dictionary<string, string> dataCollection = new Dictionary<string, string>();
                        dataCollection.Add("max_id", (Int64.Parse(tweets.Last().TweetId) - 1).ToString());
                        loadingIndicatorController.Add();
                        OAuthHelper.AccessProtectedResource(ConfigHelper.TimelineAPI, dataCollection, GetMoreTimeLineCompleted, null);
                    }
                }
                else
                {
                    //this.tweetPivotItem.Header = "middle";
                }
            }
        }

        private void FillTweetCollection(IEnumerable<XElement> xmlTweets, bool isInsert)
        {
            foreach (var item in xmlTweets)
            {
                string pictureUrl = string.Empty;
                if (item.Element("original_pic") != null)
                {
                    pictureUrl = item.Element("original_pic").Value;
                }

                string retweetText = string.Empty;
                if (item.Element("retweeted_status") != null)
                {
                    if (item.Element("retweeted_status").Element("deleted") != null)
                    {
                        retweetText = "此微博已被原作者删除。";
                    }
                    else
                    {
                        retweetText = "@" + item.Element("retweeted_status").Element("user").Element("screen_name").Value + "：" + item.Element("retweeted_status").Element("text").Value;
                        if (item.Element("retweeted_status").Element("original_pic") != null)
                        {
                            pictureUrl = item.Element("retweeted_status").Element("original_pic").Value;
                        }
                    }
                }

                Tweet tweet = new Tweet(item.Element("user").Element("id").Value, 
                                        item.Element("user").Element("screen_name").Value,
                                        item.Element("user").Element("profile_image_url").Value, 
                                        item.Element("id").Value, 
                                        item.Element("text").Value, 
                                        retweetText, 
                                        pictureUrl, 
                                        DateTimeOffset.ParseExact(item.Element("created_at").Value, "ddd MMM dd H:mm:ss zzzz yyyy", CultureInfo.InvariantCulture));
                if (isInsert == true)
                {
                    this.tweets.Insert(0, tweet);
                }
                else
                {
                    this.tweets.Add(tweet);
                }
            }
        }

        private void GetMoreTimeLineCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            IEnumerable<XElement> xmlTweets = xmlResult.Root.Elements("statuses");
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    this.FillTweetCollection(xmlTweets, false);
                    isGettingTweet = false;
                    loadingIndicatorController.Minus();
                }
            );
        }

        private void logoutMenuItem_Click(object sender, EventArgs e)
        {
            this.NavigationService.Navigate(new Uri("/Authentication.xaml", UriKind.Relative));
        }

        private void aboutMenuItem_Click(object sender, EventArgs e)
        {
            string version = Assembly.GetExecutingAssembly().FullName.Split(',')[1].Split('=')[1];
            MessageBox.Show("Weibo.NET v" + version, "关于", MessageBoxButton.OK);
        }

        private void refreshButton_Click(object sender, EventArgs e)
        {
            foreach (var item in this.tweets)
            {
                item.UpdateCreatedTimeForShow();
            }

            if (isGettingTweet == false)
            {
                isGettingTweet = true;
                Dictionary<string, string> dataCollection = new Dictionary<string, string>();
                string sinceId;
                if (tweets.Count > 0)
                {
                    sinceId = Int64.Parse(tweets.First().TweetId).ToString();
                }
                else
                {
                    sinceId = "0";
                }
                dataCollection.Add("since_id", sinceId);
                loadingIndicatorController.Add();
                OAuthHelper.AccessProtectedResource(ConfigHelper.TimelineAPI, dataCollection, GetLatestTimeLineCompleted, null);
            }
        }

        private void GetLatestTimeLineCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            IEnumerable<XElement> xmlTweets = xmlResult.Root.Elements("statuses").Reverse();
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    this.FillTweetCollection(xmlTweets, true);
                    isGettingTweet = false;
                    loadingIndicatorController.Minus();
                }
            );
        }

        private void Tweet_Loaded(object sender, RoutedEventArgs e)
        {
            StackPanel tweetListItem = sender as StackPanel;
            tweetListItem.Loaded -= Tweet_Loaded;
            Tweet tweet = tweetListItem.DataContext as Tweet;

            ContextMenu menu = new ContextMenu();
            menu.DataContext = tweet;
            menu.IsZoomEnabled = false;

            MenuItem item;
            item = new MenuItem();
            item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
            item.Header = "转发";
            item.Click += new RoutedEventHandler(RetweetItem_Click);
            menu.Items.Add(item);

            if (ConfigHelper.UserId == tweet.UserId)
            {
                item = new MenuItem();
                item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
                item.Header = "删除";
                item.Click += new RoutedEventHandler(DeleteItem_Click);
                menu.Items.Add(item);
            }

            if (tweet.PictureUrl != string.Empty)
            {
                item = new MenuItem();
                item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
                item.Header = "图片";
                item.Click += new RoutedEventHandler(Picture_Click);
                menu.Items.Add(item);
            }

            string tweetText = tweet.TweetText;
            if (tweet.RetweetText != string.Empty)
            {
                tweetText = tweetText + tweet.RetweetText;
            }

            string pattern = @"http://[a-z0-9A-Z\./%:=&\?\+]*";
            Regex reg = new Regex(pattern, RegexOptions.IgnoreCase);
            MatchCollection matchCollection = reg.Matches(tweetText);
            if (matchCollection.Count > 0)
            {
                foreach (Match match in matchCollection)
                {
                    if (menu.Items.Where(p => ((p as MenuItem).Header) as string == match.Value).Count() == 0)
                    {
                        item = new MenuItem();
                        item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
                        item.Header = match.Value;
                        item.Click += new RoutedEventHandler(Url_Click);
                        menu.Items.Add(item);
                    }
                }
            }

            ContextMenuService.SetContextMenu(tweetListItem, menu);
        }

        private void Url_Click(object sender, RoutedEventArgs e)
        {
            string url = (sender as MenuItem).Header as string;
            this.NavigationService.Navigate(new Uri("/UrlViewer.xaml?url=" + url, UriKind.Relative));
        }

        private void Picture_Click(object sender, RoutedEventArgs e)
        {
            Tweet tweet = (sender as MenuItem).DataContext as Tweet;
            this.NavigationService.Navigate(new Uri("/UrlViewer.xaml?url=" + tweet.PictureUrl, UriKind.Relative));
        }

        private void RetweetItem_Click(object sender, RoutedEventArgs e)
        {
            Tweet tweet = (sender as MenuItem).DataContext as Tweet;
            tweetForReply = tweet;
            if (tweetForReply.RetweetText == string.Empty)
            {
                this.tweetTextBox.Text = string.Empty;
                this.retweetTextBlock.Text = "@" + this.tweetForReply.ScreenName + "：" + this.tweetForReply.TweetText;
            }
            else
            {
                this.tweetTextBox.Text = @"//@" + this.tweetForReply.ScreenName + "：" + this.tweetForReply.TweetText;
                this.retweetTextBlock.Text = this.tweetForReply.RetweetText;
            }

            this.retweetTextBlock.Visibility = System.Windows.Visibility.Visible;
            this.tweetImageContainer.Visibility = System.Windows.Visibility.Collapsed;
            barIconButtonCollection["pictureButton"].IsEnabled = false;

            this.mainPivot.LoadedPivotItem += FocusTweetTextBox;
            this.mainPivot.SelectedItem = this.writeTweetPivotItem;
        }

        private void DeleteItem_Click(object sender, RoutedEventArgs e)
        {
            Tweet tweet = (sender as MenuItem).DataContext as Tweet;
            Dictionary<string, string> dataCollection = new Dictionary<string, string>();
            dataCollection.Add("id", tweet.TweetId);
            OAuthHelper.AccessProtectedResource(ConfigHelper.DeleteTweetAPI, dataCollection, null, null);
            this.tweets.Remove(tweet);
        }

        private void TweetText_Loaded(object sender, RoutedEventArgs e)
        {
            TextBlock tweetTextBlock = sender as TextBlock;
            tweetTextBlock.Loaded -= TweetText_Loaded;
            Tweet tweet = tweetTextBlock.DataContext as Tweet;

            HightLightUrl(tweetTextBlock, tweet.TweetText, tweetTextBlock.Foreground);

            if (tweet.RetweetText != string.Empty)
            {
                HightLightUrl(tweetTextBlock, " //" + tweet.RetweetText, new SolidColorBrush(Color.FromArgb(0xff, 0x00, 0x20, 0x60)));
            }

            if (tweet.PictureUrl != string.Empty)
            {
                tweetTextBlock.Inlines.Add(new Run() { Text = " 图", Foreground = new SolidColorBrush(Color.FromArgb(0xff, 0xc0, 0x50, 0x4d)) });
            }
        }

        private void HightLightUrl(TextBlock tweetTextBlock, string tweetText, Brush brush)
        {
            string pattern = @"http://[a-z0-9A-Z\./%:=&\?\+]*";
            Regex reg = new Regex(pattern, RegexOptions.IgnoreCase);
            MatchCollection matchCollection = reg.Matches(tweetText);
            if (matchCollection.Count > 0)
            {
                for (int i = 0; i < matchCollection.Count; i++)
                {
                    int begin;
                    if (i == 0)
                    {
                        begin = 0;
                    }
                    else
                    {
                        begin = matchCollection[i - 1].Index + matchCollection[i - 1].Length;
                    }
                    string temp = tweetText.Substring(begin, matchCollection[i].Index - begin);
                    if (string.IsNullOrEmpty(temp) == false)
                    {
                        tweetTextBlock.Inlines.Add(new Run() { Text = temp, Foreground = brush });
                    }
                    tweetTextBlock.Inlines.Add(new Run() { Text = matchCollection[i].Value, Foreground = new SolidColorBrush(Color.FromArgb(0xff, 0x13, 0x64, 0xc4)) });

                    if (i == matchCollection.Count - 1)
                    {
                        int lastBegin = matchCollection[i].Index + matchCollection[i].Length;
                        if (lastBegin <= tweetText.Length - 1)
                        {
                            temp = tweetText.Substring(lastBegin);
                            tweetTextBlock.Inlines.Add(new Run() { Text = temp, Foreground = brush });
                        }
                    }
                }
            }
            else
            {
                tweetTextBlock.Inlines.Add(new Run() { Text = tweetText, Foreground = brush });
            }
        }

        private void mainPivot_LoadedPivotItem(object sender, PivotItemEventArgs e)
        {
            this.ApplicationBar.Buttons.Clear();

            if (e.Item == this.tweetPivotItem)
            {
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["writeButton"]);
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["refreshButton"]);
            }

            if (e.Item == this.writeTweetPivotItem)
            {
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["publishButton"]);
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["pictureButton"]);
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["cancelButton"]);
            }

            if (e.Item == this.followingPivotItem)
            {
                if (this.followingGrid.Visibility == System.Windows.Visibility.Visible)
                {
                    this.ApplicationBar.Buttons.Add(barIconButtonCollection["followButton"]);
                }
                else
                {
                    this.ApplicationBar.Buttons.Add(barIconButtonCollection["searchUserButton"]);
                    this.ApplicationBar.Buttons.Add(barIconButtonCollection["addUserButton"]);
                    this.ApplicationBar.Buttons.Add(barIconButtonCollection["returnButton"]);
                }
            }
        }

        private void mainPivot_UnloadingPivotItem(object sender, PivotItemEventArgs e)
        {
            if (e.Item == this.writeTweetPivotItem)
            {
                this.Focus();
            }
        }

        private void tweetTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            int charCountLimit = 280;
            int charCount = CommonHelper.GetCharCountInAscii(this.tweetTextBox.Text);
            int rest = charCountLimit - charCount;
            if (rest >= 0)
            {
                validCharCount.Text = rest.ToString();
                if (this.validCharCountTextBlock.Opacity == 0)
                {
                    this.invalidCharCountTextBlock.Opacity = 0;
                    this.validCharCountTextBlock.Opacity = 1;
                }
            }
            else
            { 
                int exceed = rest * -1;
                invalidCharCount.Text = exceed.ToString();
                if (this.invalidCharCountTextBlock.Opacity == 0)
                {
                    this.validCharCountTextBlock.Opacity = 0;
                    this.invalidCharCountTextBlock.Opacity = 1;
                }
            }

            if (this.tweetTextBox.Text == string.Empty || rest < 0)
            {
                barIconButtonCollection["publishButton"].IsEnabled = false;
            }
            else
            {
                barIconButtonCollection["publishButton"].IsEnabled = true;
            }
        }

        private void userNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (this.userNameTextBox.Text == string.Empty)
            {
                barIconButtonCollection["searchUserButton"].IsEnabled = false;
            }
            else
            {
                barIconButtonCollection["searchUserButton"].IsEnabled = true;
            }
        }

        private Tweet tweetForReply = null;

        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.tweetTextBox.ReInite();
        }

        private void pictureButton_Click(object sender, EventArgs e)
        {
            PhotoChooserTask task = new PhotoChooserTask();
            task.ShowCamera = true;
            task.Completed += PhotoChooseCompleted;
            task.Show();
        }

        private void followButton_Click(object sender, EventArgs e)
        {
            this.ApplicationBar.Buttons.Clear();
            SlideTransition slidetransition = new SlideTransition();
            slidetransition.Mode = SlideTransitionMode.SlideUpFadeOut;
            ITransition transition = slidetransition.GetTransition(this.followingGrid);
            transition.Completed += (s1, e1) =>
            {
                this.followingGrid.Visibility = System.Windows.Visibility.Collapsed;
                this.followGrid.Visibility = System.Windows.Visibility.Visible;
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["searchUserButton"]);
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["addUserButton"]);
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["returnButton"]);
                slidetransition.Mode = SlideTransitionMode.SlideUpFadeIn;
                transition = slidetransition.GetTransition(this.followGrid);
                transition.Begin();
            };
            transition.Begin();
        }

        private void returnButton_Click(object sender, EventArgs e)
        {
            this.userNameTextBox.ReInite();
            this.userInfoPanel.Visibility = System.Windows.Visibility.Collapsed;
            this.noUserTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            barIconButtonCollection["addUserButton"].IsEnabled = false;
            
            this.ApplicationBar.Buttons.Clear();
            SlideTransition slidetransition = new SlideTransition();
            slidetransition.Mode = SlideTransitionMode.SlideDownFadeOut;
            ITransition transition = slidetransition.GetTransition(this.followGrid);
            transition.Completed += (s1, e1) =>
            {
                this.followGrid.Visibility = System.Windows.Visibility.Collapsed;
                this.followingGrid.Visibility = System.Windows.Visibility.Visible;
                this.ApplicationBar.Buttons.Add(barIconButtonCollection["followButton"]);
                slidetransition.Mode = SlideTransitionMode.SlideDownFadeIn;
                transition = slidetransition.GetTransition(this.followingGrid);
                transition.Begin();
            };
            transition.Begin();          
        }

        private void searchUserButton_Click(object sender, EventArgs e)
        {
            if (this.userNameTextBox.IsFocused == true)
            {
                this.Focus();
            }

            Dictionary<string, string> dataCollection = new Dictionary<string, string>();
            dataCollection.Add("screen_name", this.userNameTextBox.Text.Trim());
            loadingIndicatorController.Add();
            OAuthHelper.AccessProtectedResource(ConfigHelper.UserInfoAPI, dataCollection, GetUserInfoCompleted, null);
        }

        private void GetUserInfoCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            XElement xmlUserInfo = xmlResult.Root;
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    User.GenderEnum gender = User.GenderEnum.Unknown;
                    switch (xmlUserInfo.Element("gender").Value)
                    {
                        case "m":
                            gender = User.GenderEnum.Male;
                            break;
                        case "f":
                            gender = User.GenderEnum.Female;
                            break;
                        case "n":
                            gender = User.GenderEnum.Unknown;
                            break;
                    }
                    User user = new User(xmlUserInfo.Element("id").Value,
                                         xmlUserInfo.Element("screen_name").Value,
                                         xmlUserInfo.Element("location").Value,
                                         xmlUserInfo.Element("description").Value,
                                         xmlUserInfo.Element("profile_image_url").Value,
                                         gender,
                                         bool.Parse(xmlUserInfo.Element("following").Value),
                                         bool.Parse(xmlUserInfo.Element("follow_me").Value));

                    this.userInfoPanel.DataContext = user;

                    this.userInfoPanel.Visibility = System.Windows.Visibility.Visible;
                    this.noUserTextBlock.Visibility = System.Windows.Visibility.Collapsed;
                    if (user.Followed == true || user.UserId == ConfigHelper.UserId)
                    {
                        barIconButtonCollection["addUserButton"].IsEnabled = false;
                    }
                    else
                    {
                        barIconButtonCollection["addUserButton"].IsEnabled = true;
                    }

                    loadingIndicatorController.Minus();
                }
            );
        }

        private void addUserButton_Click(object sender, EventArgs e)
        {
            this.userNameTextBox.ReInite();
            this.userInfoPanel.Visibility = System.Windows.Visibility.Collapsed;
            barIconButtonCollection["addUserButton"].IsEnabled = false;

            Dictionary<string, string> dataCollection = new Dictionary<string, string>();
            User user = this.userInfoPanel.DataContext as User;
            dataCollection.Add("uid", user.UserId);
            loadingIndicatorController.Add();
            OAuthHelper.AccessProtectedResource(ConfigHelper.FollowAPI, dataCollection, FollowCompleted, user);
        }

        private void FollowCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    loadingIndicatorController.Minus();
                    if (followingListBox.Visibility == System.Windows.Visibility.Visible)
                    {
                        User user = userState as User;
                        following.Insert(0, user);
                    }
                }
            );
        }

        private PhotoResult pictureFile;

        private void PhotoChooseCompleted(object sender, PhotoResult e)
        {
            if (e.TaskResult == TaskResult.OK)
            {
                string fileExtension = Path.GetExtension(e.OriginalFileName);
                if (CommonHelper.IsValidPictureType(fileExtension) == true)
                {
                    if (this.tweetTextBox.Text == string.Empty)
                    {
                        this.tweetTextBox.Text = "分享图片";
                    }
                    pictureFile = e;
                    BitmapImage bitmapImage = this.tweetImage.Source as BitmapImage;
                    bitmapImage.UriSource = new Uri(pictureFile.OriginalFileName);
                    this.tweetImageContainer.Visibility = System.Windows.Visibility.Visible;
                }
                else
                {
                    pictureFile = null;
                    this.tweetImageContainer.Visibility = System.Windows.Visibility.Collapsed;
                }
            }
        }

        private void publishButton_Click(object sender, EventArgs e)
        {
            if (tweetForReply == null)
            {
                if (this.tweetImageContainer.Visibility == System.Windows.Visibility.Visible)
                {
                    Dictionary<string, object> dataCollection = new Dictionary<string, object>();
                    dataCollection.Add("status", this.tweetTextBox.Text);
                    dataCollection.Add("pic", new MultipartData(Path.GetFileName(pictureFile.OriginalFileName), pictureFile.ChosenPhoto));
                    OAuthHelper.PostProtectedResourceWithMultipart(ConfigHelper.PublishTweetWithImageAPI, dataCollection, PublishTweetCompleted, null);
                }
                else
                {
                    Dictionary<string, string> dataCollection = new Dictionary<string, string>();
                    dataCollection.Add("status", this.tweetTextBox.Text);
                    OAuthHelper.AccessProtectedResource(ConfigHelper.PublishTweetAPI, dataCollection, PublishTweetCompleted, null);
                }
            }
            else
            {
                Dictionary<string, string> dataCollection = new Dictionary<string, string>();
                dataCollection.Add("id", tweetForReply.TweetId);
                dataCollection.Add("status", this.tweetTextBox.Text);
                OAuthHelper.AccessProtectedResource(ConfigHelper.PublishRetweetAPI, dataCollection, PublishTweetCompleted, null);
            }
            loadingIndicatorController.Add();
            this.tweetTextBox.ReInite();
        }

        private void PublishTweetCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            this.Dispatcher.BeginInvoke
            (
                () => 
                {
                    refreshButton_Click(null, null);
                    loadingIndicatorController.Minus();
                }
            );
        }

        private void writeButton_Click(object sender, EventArgs e)
        {
            tweetForReply = null;
            this.tweetTextBox.Text = string.Empty;
            this.retweetTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            this.tweetImageContainer.Visibility = System.Windows.Visibility.Collapsed;
            barIconButtonCollection["pictureButton"].IsEnabled = true;
            this.mainPivot.LoadedPivotItem += FocusTweetTextBox;
            this.mainPivot.SelectedItem = this.writeTweetPivotItem;
        }

        private void FocusTweetTextBox(object sender, PivotItemEventArgs e)
        {
            this.mainPivot.LoadedPivotItem -= FocusTweetTextBox;
            this.tweetTextBox.Focus();
        }

        private void tweetTextBox_WatermarkHidden(object sender, EventArgs e)
        {
            if (tweetForReply == null)
            {
                barIconButtonCollection["pictureButton"].IsEnabled = true;
            }
            else
            {
                barIconButtonCollection["pictureButton"].IsEnabled = false;
            }
            barIconButtonCollection["cancelButton"].IsEnabled = true;
        }

        private void tweetTextBox_WatermarkShown(object sender, EventArgs e)
        {
            tweetForReply = null;
            pictureFile = null;
            this.retweetTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            this.tweetImageContainer.Visibility = System.Windows.Visibility.Collapsed;
            barIconButtonCollection["pictureButton"].IsEnabled = false;
            barIconButtonCollection["cancelButton"].IsEnabled = false;
        }

        public void RestorePageStateForException(WebException ex)
        {
            string errorMessage = ex.Message;
            string requestUri = ex.Data["RequestUri"] as string;
            if (ex.Status == WebExceptionStatus.RequestCanceled)
            {
                errorMessage = "请求超时";
            }
            else
            {
                string badRequestContent = ex.Data["BadRequestContent"] as string;
                if (string.IsNullOrEmpty(badRequestContent) == false)
                {
                    if (requestUri.Contains(ConfigHelper.UserInfoAPI.APIUrl) == true && badRequestContent.Contains("20003") == true)
                    {
                        this.userInfoPanel.Visibility = System.Windows.Visibility.Collapsed;
                        this.noUserTextBlock.Visibility = System.Windows.Visibility.Visible;
                        barIconButtonCollection["addUserButton"].IsEnabled = false;
                        loadingIndicatorController.Minus();
                        return;
                    }
                    else
                    {
                        errorMessage = badRequestContent;
                    }
                }
            }

            CommonHelper.ShowErrorMessage(errorMessage);

            if (requestUri.Contains(ConfigHelper.DeleteTweetAPI.APIUrl) == true || requestUri.Contains(ConfigHelper.UnfollowAPI.APIUrl) == true)
            {
                return;
            }

            if (requestUri.Contains(ConfigHelper.TimelineAPI.APIUrl) == true)
            {
                isGettingTweet = false;
            }

            loadingIndicatorController.Minus();
        }

        private class LoadingIndicatorController
        {
            public LoadingIndicatorController(LoadingIndicator loadingIndicator)
            {
                waitingCount = 0;
                this.loadingIndicator = loadingIndicator;
            }

            private int waitingCount;
            private LoadingIndicator loadingIndicator;

            public void Add()
            {
                if (waitingCount == 0)
                {
                    this.loadingIndicator.Begin(); 
                }
                waitingCount++;
            }

            public void Minus()
            {
                if (waitingCount > 0)
                {
                    waitingCount--;
                }
                if (waitingCount == 0)
                {
                    this.loadingIndicator.Stop();
                }
            }
        }

        private void followingHintContainer_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            this.followingListBox.ItemsSource = this.following;

            this.followingHintContainer.Visibility = System.Windows.Visibility.Collapsed;
            this.followingListBox.Visibility = System.Windows.Visibility.Visible;

            Dictionary<string, string> dataCollection = new Dictionary<string, string>();
            dataCollection.Add("uid", ConfigHelper.UserId);
            dataCollection.Add("count", "200");
            loadingIndicatorController.Add();
            OAuthHelper.AccessProtectedResource(ConfigHelper.GetFollowingAPI, dataCollection, GetFollowingCompleted, null);
        }

        private void GetFollowingCompleted(HttpWebResponse response, XDocument xmlResult, object userState)
        {
            IEnumerable<XElement> xmlFollowing = xmlResult.Root.Elements("users");
            this.Dispatcher.BeginInvoke
            (
                () =>
                {
                    foreach (var item in xmlFollowing)
                    {
                        User.GenderEnum gender = User.GenderEnum.Unknown;
                        switch (item.Element("gender").Value)
                        {
                            case "m":
                                gender = User.GenderEnum.Male;
                                break;
                            case "f":
                                gender = User.GenderEnum.Female;
                                break;
                            case "n":
                                gender = User.GenderEnum.Unknown;
                                break;
                        }

                        User user = new User(item.Element("id").Value,
                                             item.Element("screen_name").Value,
                                             item.Element("location").Value,
                                             item.Element("description").Value,
                                             item.Element("profile_image_url").Value,
                                             gender,
                                             bool.Parse(item.Element("following").Value),
                                             bool.Parse(item.Element("follow_me").Value));
                        this.following.Add(user);
                    }

                    ScrollViewer scrollViewer = VisualTreeHelper.GetChild(this.followingListBox, 0) as ScrollViewer;
                    List<ScrollBar> scrollBarList = CommonHelper.GetVisualChildCollection<ScrollBar>(scrollViewer);
                    ScrollBar bar = scrollBarList.Where(x => x.Name == "VerticalScrollBar").First();
                    bar.Background = new SolidColorBrush(Color.FromArgb(0xff, 0x99, 0x99, 0x99));

                    loadingIndicatorController.Minus();
                }
            );
        }

        private void Following_Loaded(object sender, RoutedEventArgs e)
        {
            StackPanel followingItem = sender as StackPanel;
            followingItem.Loaded -= Tweet_Loaded;
            User user = followingItem.DataContext as User;

            ContextMenu menu = new ContextMenu();
            menu.DataContext = user;
            menu.IsZoomEnabled = false;

            MenuItem item;
            item = new MenuItem();
            item.SetValue(TiltEffect.IsTiltEnabledProperty, true);
            item.Header = "取消关注";
            item.Click += new RoutedEventHandler(UnfollowItem_Click);
            menu.Items.Add(item);

            ContextMenuService.SetContextMenu(followingItem, menu);
        }

        private void UnfollowItem_Click(object sender, RoutedEventArgs e)
        {
            User user = (sender as MenuItem).DataContext as User;
            Dictionary<string, string> dataCollection = new Dictionary<string, string>();
            dataCollection.Add("uid", user.UserId);
            OAuthHelper.AccessProtectedResource(ConfigHelper.UnfollowAPI, dataCollection, null, null);
            this.following.Remove(user);
        }

        private void PhoneApplicationPage_BackKeyPress(object sender, CancelEventArgs e)
        {
            while (this.NavigationService.CanGoBack == true)
            {
                this.NavigationService.RemoveBackEntry();
            }
        }
    }

    public class Tweet : INotifyPropertyChanged
    {
        public Tweet(string userId, string screenName, string userProfileImageUrl, string tweetId, string tweetText, string retweetText, string pictureUrl, DateTimeOffset createdTime)
        {
            TweetId = tweetId;
            UserId = userId;
            ScreenName = screenName;
            UserProfileImageUrl = userProfileImageUrl;
            TweetText = tweetText;
            RetweetText = retweetText;
            PictureUrl = pictureUrl;
            CreatedTime = createdTime;
        }

        public string TweetId { get; private set; }

        public string UserId { get; private set; }

        public string UserProfileImageUrl { get; private set; }

        public string ScreenName { get; private set; }

        public string TweetText { get; private set; }

        public string RetweetText { get; private set; }

        public string PictureUrl { get; private set; }

        public DateTimeOffset CreatedTime { get; private set; }

        public string CreatedTimeForShow
        {
            get
            {
                TimeSpan span = DateTimeOffset.Now - this.CreatedTime;
                string formattedTime = string.Empty;

                if (span.TotalHours > 24)
                {
                    formattedTime = this.CreatedTime.ToLocalTime().ToString("M", new CultureInfo("zh-CN"));
                }
                else
                {
                    if (span.TotalMinutes > 60)
                    {
                        formattedTime = string.Format("{0}小时前", ((int)span.TotalHours).ToString());
                    }
                    else
                    {
                        formattedTime = string.Format("{0}分钟前", ((int)span.TotalMinutes).ToString());
                    }
                }
                return formattedTime;
            }
        }

        public void UpdateCreatedTimeForShow()
        {
            this.OnPropertyChanged("CreatedTimeForShow");
        }

        private void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class UserImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string imageUrl = (string)value;
            return ProfileImageCache.GetProfileImage(imageUrl);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class ProfileImageCache
    {
        private static Dictionary<string, BitmapImage> profileImageCache = new Dictionary<string, BitmapImage>();

        private static object syncObject = new object();

        public static BitmapImage GetProfileImage(string imageUrl)
        {
            BitmapImage image;
            bool downloadImage = false;

            lock (syncObject)
            {
                if (profileImageCache.ContainsKey(imageUrl) == true)
                {
                    image = profileImageCache[imageUrl];
                }
                else
                {
                    downloadImage = true;
                    image = new BitmapImage();
                    profileImageCache.Add(imageUrl, image);
                }
            }

            if (downloadImage == true)
            {
                HttpWebRequest request = WebRequest.CreateHttp(new Uri(imageUrl, UriKind.Absolute));
                request.Method = "GET";
                DownloadImageState state = new DownloadImageState(request, image);
                request.BeginGetResponse(DownloadImageCompleted, state);
            }

            return image;
        }

        private static void DownloadImageCompleted(IAsyncResult asyncResult)
        {
            DownloadImageState state = asyncResult.AsyncState as DownloadImageState;
            HttpWebResponse response = null;
            try
            {
                response = state.Request.EndGetResponse(asyncResult) as HttpWebResponse;
            }
            catch (WebException)
            {
                return;
            }

            MemoryStream imageStream = new MemoryStream();
            Stream stream = response.GetResponseStream();
            stream.CopyTo(imageStream);
            response.Close();

            bool isGif = false;
            if (response.Headers["Content-Type"] == "image/gif")
            {
                isGif = true;
            }

            BitmapImage image = state.Image;
            image.Dispatcher.BeginInvoke
            (
                () =>
                {
                    if (isGif == true)
                    {
                        GifDecoder gifDecoder = new GifDecoder();
                        ExtendedImage img = new ExtendedImage();
                        imageStream.Position = 0;
                        gifDecoder.Decode(img, imageStream);
                        WriteableBitmap wb = new WriteableBitmap(img.PixelWidth, img.PixelHeight);
                        for (int i = 0; i < wb.Pixels.Length; i++)
                        {
                            wb.Pixels[i] = CommonHelper.CalcWritableBitmapPixelValue(img.Pixels[i * 4 + 3], img.Pixels[i * 4], img.Pixels[i * 4 + 1], img.Pixels[i * 4 + 2]);
                        }
                        imageStream.Close();
                        imageStream = new MemoryStream();
                        wb.SaveJpeg(imageStream, wb.PixelWidth, wb.PixelHeight, 0, 100);
                    }

                    image.SetSource(imageStream);
                    imageStream.Close();
                }
            );
        }

        private class DownloadImageState
        {
            public DownloadImageState(HttpWebRequest request, BitmapImage image)
            {
                this.Request = request;
                this.Image = image;
            }

            public HttpWebRequest Request { get; private set; }
            public BitmapImage Image { get; private set; }
        }
    }

    public class User
    {
        public User(string userId, string screenName, string location, string description, string profileImageUrl, GenderEnum gender, bool followed, bool followMe)
        {
            UserId = userId;
            ScreenName = screenName;
            Location = location;
            Description = description;
            ProfileImageUrl = profileImageUrl;
            Gender = gender;
            Followed = followed;
            FollowMe = followMe;
        }

        public string UserId { get; private set; }

        public string ScreenName { get; private set; }

        public string Location { get; private set; }

        public string Description { get; private set; }

        public string ProfileImageUrl { get; private set; }

        public GenderEnum Gender { get; private set; }

        public bool Followed { get; private set; }

        public bool FollowMe { get; private set; }

        public enum GenderEnum
        { 
            Male,
            Female,
            Unknown
        }
    }

    public class GenderImageConverter : IValueConverter
    {
        private static BitmapImage maleImage = new BitmapImage(new Uri("/UI;component/Images/male.png", UriKind.Relative));

        private static BitmapImage femaleImage = new BitmapImage(new Uri("/UI;component/Images/female.png", UriKind.Relative));

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            User.GenderEnum gender = (User.GenderEnum)value;
            BitmapImage genderImage = null;
            switch (gender)
            { 
                case User.GenderEnum.Male:
                    genderImage = GenderImageConverter.maleImage;
                    break;
                case User.GenderEnum.Female:
                    genderImage = GenderImageConverter.femaleImage;
                    break;
            }
            return genderImage;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class FollowMeStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            bool followMe = (bool)value;
            return followMe == true ? "互关注" : string.Empty;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class FollowedStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            User user = (User)value;
            string error = string.Empty;
            if (user.UserId == ConfigHelper.UserId)
            {
                error = "自己";
            }
            else
            {
                if (user.Followed == true)
                {
                    error = "已关注";
                }
            }
            return error;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}